package com.bingxue.edu.management.education.service.exam;

import com.bingxue.edu.common.enums.QuestionTypeEnum;
import com.bingxue.edu.framework.common.util.ValidationUtils;
import com.bingxue.edu.framework.mybatis.base.BaseService;
import com.bingxue.edu.management.education.mapper.exam.ExamRecordMapper;
import com.bingxue.edu.management.education.model.entity.exam.Exam;
import com.bingxue.edu.management.education.model.entity.exam.ExamQuestion;
import com.bingxue.edu.management.education.model.entity.exam.ExamRecord;
import com.bingxue.edu.management.education.model.resp.exam.ExamRecordAggregateResp;
import com.bingxue.edu.management.education.model.resp.exam.ExamScoreTableResp;
import com.bingxue.edu.management.education.model.resp.exam.QuestionSet;
import com.bingxue.edu.management.education.model.resp.exam.ScoreItem;
import com.bingxue.edu.parent.model.resp.ExamQuestionDistResp;
import com.bingxue.edu.parent.model.resp.ExamScoreDistResp;
import com.mybatisflex.core.query.QueryWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors;

import static com.bingxue.edu.management.education.model.entity.exam.table.ExamAnswerRecordTableDef.EXAM_ANSWER_RECORD;
import static com.bingxue.edu.management.education.model.entity.exam.table.ExamRecordTableDef.EXAM_RECORD;
import static com.bingxue.edu.management.education.model.entity.table.ClassInfoTableDef.CLASS_INFO;
import static com.bingxue.edu.management.education.model.entity.table.StudentTableDef.STUDENT;

@Slf4j
@Service
@RequiredArgsConstructor
public class ExamRecordService extends BaseService<ExamRecordMapper, ExamRecord> {
    private final ExamService examService;
    private final ExamQuestionService examQuestionService;

    public void removeByExamId(String examId) {
        QueryWrapper removeExamRecordQueryWrapper = QueryWrapper.create()
                .where(EXAM_RECORD.EXAM_ID.eq(examId));
        this.remove(removeExamRecordQueryWrapper);
    }

    public List<ExamRecordAggregateResp> getExamRecordAggregateList(String examId) {
        QueryWrapper queryWrapper = QueryWrapper.create()
                .select(EXAM_RECORD.ALL_COLUMNS,
                        EXAM_ANSWER_RECORD.QUESTION_ID,
                        EXAM_ANSWER_RECORD.CORRECTED,
                        EXAM_ANSWER_RECORD.SCORE,
                        STUDENT.NAME.as(ExamRecordAggregateResp::getStudentName),
                        CLASS_INFO.NAME.as(ExamRecordAggregateResp::getClassName),
                        CLASS_INFO.LEAD_TEACHER_ID.as(ExamRecordAggregateResp::getLeadTeacherId)
                )
                .from(EXAM_RECORD)
                .leftJoin(STUDENT).on(STUDENT.ID.eq(EXAM_RECORD.STUDENT_ID))
                .leftJoin(CLASS_INFO).on(CLASS_INFO.ID.eq(EXAM_RECORD.CLASS_ID))
                .leftJoin(EXAM_ANSWER_RECORD).on(EXAM_ANSWER_RECORD.EXAM_RECORD_ID.eq(EXAM_RECORD.ID))
                .where(EXAM_RECORD.EXAM_ID.eq(examId));
        return this.getMapper().selectListWithRelationsByQueryAs(queryWrapper, ExamRecordAggregateResp.class);
    }

    public ExamScoreTableResp getScoreTable(String examId) {
        ExamScoreTableResp examScoreTable = new ExamScoreTableResp();
        Exam exam = examService.getById(examId);
        ValidationUtils.throwIfNull(exam,"考试信息不存在");
        // 组装考试题目
        List<ExamQuestion> questionsList = examQuestionService.getListByExamId(examId);
        TreeMap<String, List<ExamQuestion>> collect = questionsList.stream().collect(Collectors.groupingBy(
                ExamQuestion::getQuestionType,
                TreeMap::new,
                Collectors.collectingAndThen(Collectors.toList(), list -> list.stream().sorted(Comparator.comparing(ExamQuestion::getQuestionIndex)).collect(Collectors.toList()))
        ));
        List<QuestionSet> questionSets = new LinkedList<>();
        collect.forEach((key, value) -> {
            QuestionSet questionSet = new QuestionSet();
            questionSet.setKey(key);
            questionSet.setTitle(key);
            questionSet.setQuestions(value);
            questionSets.add(questionSet);
        });
        // 查询考试记录
        List<ExamRecordAggregateResp> examRecordAggregateList = this.getExamRecordAggregateList(examId);
        for (ExamRecordAggregateResp examRecord : examRecordAggregateList) {
            Map<String, ScoreItem> answerRecordsMap = examRecord.getScoreItemList().stream().collect(Collectors.toMap(ScoreItem::getQuestionId, item -> item));
            examRecord.setScoreItemMap(answerRecordsMap);
        }
        examScoreTable.setId(exam.getId());
        examScoreTable.setTitle(exam.getName());
        examScoreTable.setQuestionSets(questionSets);
        examScoreTable.setExamRecords(examRecordAggregateList);
        return examScoreTable;
    }

    public ExamQuestionDistResp getStudentScoreDist(String examId, String recordId) {
        return null;
    }

    /**
     * 计算考试成绩分布百分比
     * @param examId 考试id
     */
    public ExamScoreDistResp getScoreDist(String examId) {
        ExamScoreDistResp dist = new ExamScoreDistResp();
        Map<String, Integer> rangeMap = new HashMap<>();
        for (String range : ExamScoreDistResp.ALL_RANGES) {
            rangeMap.put(range, 0);
        }
        List<ExamRecord> recordList = this.listByIds(Collections.singleton(examId));
        for (ExamRecord record : recordList) {
            if (record.getTotalScore().compareTo(BigDecimal.valueOf(30)) < 0) {
                rangeMap.put(ExamScoreDistResp.ALL_RANGES.get(0), rangeMap.get(ExamScoreDistResp.ALL_RANGES.get(0)) + 1);
            } else if (record.getTotalScore().compareTo(BigDecimal.valueOf(40)) < 0) {
                rangeMap.put(ExamScoreDistResp.ALL_RANGES.get(1), rangeMap.get(ExamScoreDistResp.ALL_RANGES.get(1)) + 1);
            } else if (record.getTotalScore().compareTo(BigDecimal.valueOf(50)) < 0) {
                rangeMap.put(ExamScoreDistResp.ALL_RANGES.get(2), rangeMap.get(ExamScoreDistResp.ALL_RANGES.get(2)) + 1);
            } else if (record.getTotalScore().compareTo(BigDecimal.valueOf(60)) < 0) {
                rangeMap.put(ExamScoreDistResp.ALL_RANGES.get(3), rangeMap.get(ExamScoreDistResp.ALL_RANGES.get(3)) + 1);
            } else if (record.getTotalScore().compareTo(BigDecimal.valueOf(70)) < 0) {
                rangeMap.put(ExamScoreDistResp.ALL_RANGES.get(4), rangeMap.get(ExamScoreDistResp.ALL_RANGES.get(4)) + 1);
            } else if (record.getTotalScore().compareTo(BigDecimal.valueOf(80)) < 0) {
                rangeMap.put(ExamScoreDistResp.ALL_RANGES.get(5), rangeMap.get(ExamScoreDistResp.ALL_RANGES.get(5)) + 1);
            } else {
                rangeMap.put(ExamScoreDistResp.ALL_RANGES.get(6), rangeMap.get(ExamScoreDistResp.ALL_RANGES.get(6)) + 1);
            }
        }
        dist.setSeries(rangeMap);
        return dist;
    }

    /**
     * 计算考试成绩分布百分比
     * @param examId 考试id
     */
    public ExamScoreDistResp getScoreDist1(String examId) {
        ExamScoreDistResp dist = new ExamScoreDistResp();
        List<ExamRecord> recordList = this.listByIds(Collections.singleton(examId));
        List<Double> count = Arrays.asList(0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00);
        for (ExamRecord record : recordList) {
            if (record.getTotalScore().compareTo(BigDecimal.valueOf(30)) < 0) {
                count.set(0, count.get(0) + 1);
            } else if (record.getTotalScore().compareTo(BigDecimal.valueOf(40)) < 0) {
                count.set(1, count.get(1) + 1);
            } else if (record.getTotalScore().compareTo(BigDecimal.valueOf(50)) < 0) {
                count.set(2, count.get(2) + 1);
            } else if (record.getTotalScore().compareTo(BigDecimal.valueOf(60)) < 0) {
                count.set(3, count.get(3) + 1);
            } else if (record.getTotalScore().compareTo(BigDecimal.valueOf(70)) < 0) {
                count.set(4, count.get(4) + 1);
            } else if (record.getTotalScore().compareTo(BigDecimal.valueOf(80)) < 0) {
                count.set(5, count.get(5) + 1);
            } else {
                count.set(6, count.get(6) + 1);
            }
        }
        DecimalFormat df = new DecimalFormat("0.##");
        int total = recordList.size();
        List<String> data = count.stream().map(it -> total > 0 ? df.format(100 * it / total) : "0").collect(Collectors.toList());
        dist.setData(data);
        return dist;
    }
}
